package com.xms.sdk.extensions;

import com.xms.schema.entity.Attribute;
import com.xms.schema.extension.AttributeExt;
import com.xms.sdk.core.query.LinkEntity;
import com.xms.sdk.core.query.QueryExpression;
import com.xms.utils.CollectionUtil;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * QueryExpressionExt
 * </p>
 *
 * @author migo
 * @since 2021/9/6
 */
public class QueryExpressionExt {

    public static LinkEntity findLinkEntityByName(QueryExpression query, String name)
    {
        Stream<LinkEntity> filter = query.LinkEntities.stream().filter(n -> n.LinkToEntityName.equalsIgnoreCase(name));
        if (filter.count() == 0)
        {
            for (LinkEntity le : query.LinkEntities)
            {
                if (CollectionUtil.notEmpty(le.LinkEntities))
                {
                    return le.LinkEntities.stream().filter(x -> x.EntityAlias.equalsIgnoreCase(name)).findFirst().get();
                }
            }
        }
        else{
            return filter.findFirst().get();
        }
        return null;
    }
    public static List<String> getAllEntityNames(QueryExpression query){
        return getAllEntityNames(query, null);
    }

    public static List<String> getAllEntityNames(QueryExpression query, LinkEntity parent)
    {
        LinkedList<String> result = new LinkedList<>();
        if (parent == null)
        {
            result.add(query.EntityName);
            if (CollectionUtil.notEmpty(query.LinkEntities))
            {
                for (LinkEntity le : query.LinkEntities)
                {
                    if (CollectionUtil.notEmpty(le.LinkEntities))
                    {
                        getAllEntityNames(query, le);
                    }
                    else
                    {
                        result.add(le.LinkToEntityName);
                    }
                }
            }
        }
        else
        {
            result.add(parent.LinkToEntityName);
            if (CollectionUtil.notEmpty(parent.LinkEntities))
            {
                for (LinkEntity le : parent.LinkEntities)
                {
                    if (CollectionUtil.notEmpty(le.LinkEntities))
                    {
                        getAllEntityNames(query, le);
                    }
                    else
                    {
                        result.add(le.LinkToEntityName);
                    }
                }
            }
        }

        return result;
    }

    public static List<String> getAllColumns(QueryExpression query, LinkEntity lEntity, List<Attribute> attributeMetaDatas, boolean wrapName, String aliasJoiner)
    {
        List<String> result = new LinkedList<>();
        if (lEntity != null)
        {
            if (lEntity.Columns.AllColumns)
            {
                lEntity.Columns.Columns.clear();
                List<String> attributeNames = new ArrayList<>();
                attributeMetaDatas.stream().filter(x->x.getEntityname().equalsIgnoreCase(lEntity.LinkToEntityName)).forEach(f->attributeNames.add(f.getName()));
                lEntity.Columns.addColumns(attributeNames);
            }
            for (String column : lEntity.Columns.Columns)
            {
                if (wrapName)
                {
                    Stream<Attribute> filter = attributeMetaDatas.stream().filter(n -> n.getEntityname().equalsIgnoreCase(lEntity.LinkToEntityName) && n.getName().equalsIgnoreCase(column));
                    Attribute attr = filter.count() > 0 ? filter.findFirst().get() : null;
                    if (attr != null &&
                            (AttributeExt.typeIsLookUp(attr) || AttributeExt.typeIsOwner(attr) || AttributeExt.typeIsCustomer(attr)
                                    || AttributeExt.typeIsState(attr) || AttributeExt.typeIsBit(attr) || AttributeExt.typeIsPickList(attr)))
                    {
                        result.add((lEntity.EntityAlias + aliasJoiner + column + "name").toLowerCase());
                    }
                }
                result.add((lEntity.EntityAlias + aliasJoiner + column).toLowerCase());
            }
            if (CollectionUtil.notEmpty(lEntity.LinkEntities))
            {
                for (LinkEntity le : lEntity.LinkEntities)
                {
                    result.addAll(getAllColumns(query, le, attributeMetaDatas, wrapName, aliasJoiner));
                }
            }
        }
        else
        {
            if (query.ColumnSet.AllColumns)
            {
                List<String> attributeNames = new ArrayList<>();
                attributeMetaDatas.stream().filter(x->x.getEntityname().equalsIgnoreCase(query.EntityName)).forEach(f->attributeNames.add(f.getName()));
                query.ColumnSet.Columns.clear();
                query.ColumnSet.addColumns(attributeNames);
            }
            for (String column : query.ColumnSet.Columns)
            {
                if (wrapName)
                {
                    Stream<Attribute> filter = attributeMetaDatas.stream().filter(n -> n.getEntityname().equalsIgnoreCase(query.EntityName) && n.getName().equalsIgnoreCase(column));
                    Attribute attr = filter.count() > 0 ? filter.findFirst().get() : null;
                    if (attr != null &&
                            (AttributeExt.typeIsLookUp(attr) || AttributeExt.typeIsOwner(attr) || AttributeExt.typeIsCustomer(attr)
                                    || AttributeExt.typeIsState(attr) || AttributeExt.typeIsBit(attr) || AttributeExt.typeIsPickList(attr)))
                    {
                        result.add(column.toLowerCase() + "name");
                    }
                }
                result.add(column.toLowerCase());
            }
            if (CollectionUtil.notEmpty(query.LinkEntities))
            {
                for (LinkEntity le : query.LinkEntities)
                {
                    result.addAll(getAllColumns(query, le, attributeMetaDatas, wrapName, aliasJoiner));
                }
            }
        }
        if (CollectionUtil.notEmpty(result))
        {
            result = result.stream().distinct().collect(Collectors.toList());
        }
        return result;
    }
}
